﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace Jemgine.Data
{
    [Jemgine.Engine.Category("Primitive"), Jemgine.Engine.Component]
    public class Chunk : EntityElement, EditorDrawable, 
        TexturedObject, Tintable, Translatable, Rotatable, Scalable, ReferenceTarget, Jemgine.Engine.Renderer.IDrawable
	{
        public enum _BlendMode
        {
            Blend,
            Add
        }

        public int BoneID { get; set; }
        [ContentSerializerIgnore]
        public Bone BoneReference { get; set; }

		public Vector2 Position;
		public float Angle;
        public float Scale { get; set; }
        public float AspectRatio { get; set; }

        [System.ComponentModel.Editor(typeof(TextureEditor), typeof(System.Drawing.Design.UITypeEditor))]
        public String Texture { get; set; }
        public String Effect { get; set; }

        [ContentSerializer(Optional = true)]
        public Vector4 Tint { get; set; }

        [ContentSerializer(Optional = true)]
        public _BlendMode BlendMode { get; set; }

        [ContentSerializer(Optional = true)]
        public bool Flip { get; set; }

        public Chunk()
        {
            BlendMode = _BlendMode.Blend;
            Tint = Vector4.One;
            AspectRatio = 1.0f;
            Scale = 1.0f;
            Flip = false;
        }

       public void CopyFrom(Chunk B)
		{
			this.Position = B.Position;
			this.Angle = B.Angle;
			this.Scale = B.Scale;
			this.Texture = B.Texture;
            this.Effect = B.Effect;
            this.BlendMode = B.BlendMode;
            this.Tint = B.Tint;
            this.AspectRatio = B.AspectRatio;
            this.Flip = B.Flip;
            this.BoneID = B.BoneID;
		}

    	public EntityElement Clone()
		{
			Chunk C = new Chunk();
			C.CopyFrom(this);
			return C;
		}

		public static bool PointInside(Vector2 Position, Vector2 Scale, float Angle, Vector2 Point)
		{
			Vector2[] TempVectors = new Vector2[4];
			TempVectors[0] = new Vector2(-0.5f, -0.5f);
			TempVectors[1] = new Vector2(0.5f, -0.5f);
			TempVectors[2] = new Vector2(0.5f, 0.5f);
			TempVectors[3] = new Vector2(-0.5f, 0.5f);

			Matrix M =
                Matrix.CreateScale(Scale.X, Scale.Y, 1.0f) *
				Matrix.CreateRotationZ(Angle) *
				Matrix.CreateTranslation(Position.X, Position.Y, 0);

			for (int i = 0; i < 4; ++i)
				TempVectors[i] = Vector2.Transform(TempVectors[i], M);

			double angle = 0;

			for (int i = 0; i < 4; i++)
			{
				Vector2 p1 = TempVectors[i] - Point;
				Vector2 p2 = TempVectors[i == 3? 0 : i + 1] - Point;

				angle += Math.Vector.AngleBetweenVectors(p1, p2);
			}

			if (System.Math.Abs(angle) < System.Math.PI - Math.Utility.Epsilon)
				return false;

			return true;


		}

        public bool PointInside(Vector2 Point)
        {
            return Chunk.PointInside(Position, new Vector2(Scale * AspectRatio, Scale), Angle, Point);
        }

        public Jemgine.Engine.Selection.Types SelectionType()
        {
            return Jemgine.Engine.Selection.Types.EntityElement;
            //return Jemgine.Engine.Selection.Types.Chunk;
        }

        [ContentSerializerIgnore]
        public EntityRecord Owner { get; private set; }

        public void SetOwner(EntityRecord E)
        {
            Owner = E;
        }

        public void Initialize(Data.EntityRecord Self, Microsoft.Xna.Framework.Content.ContentManager Content)
        {
        }

        public void Destroy()
        { }

        #region EditorDrawable Members

        public void Draw(int ID, EditorDrawData Context,
            Data.SelectionType Selected)
        {
            if (Selected == Data.SelectionType.NotSelected)
            {
                Context.Renderer.Color = Tint;
                var Tex = Context.GetTexture(Texture);
                if (Tex != null)
                    Context.Renderer.DrawSprite(
                        Tex, Position, 
                        new Vector2(Scale * AspectRatio, Scale),
                        Angle, Flip, BlendMode == _BlendMode.Add);
            }

            if (Context.DrawSpriteOutlines)
            {
                Context.Renderer.Color = EditorDrawData.DrawColor(Selected);
                Context.Renderer.DrawSpriteOutline(Position, new Vector2(Scale * AspectRatio, Scale), Angle);
            }
        }

        #endregion

        #region TexturedObject Members

        public void SetTexture(String ID, Texture2D Texture)
        {
            this.Texture = ID;
            if (Texture != null)
                this.AspectRatio = (float)Texture.Width / (float)Texture.Height;
        }

        #endregion

        #region Tintable Members

        public void SetTint(Vector4 Tint)
        {
            this.Tint = Tint;
        }

        public Vector4 GetTint()
        {
            return Tint;
        }

        #endregion

        #region Translatable Members

        object Translatable.PrepareToTranslate()
        {
            return Position;
        }

        void Translatable.ApplyTranslation(object Tag, Vector2 MouseDelta)
        {
            Vector2 OriginalPosition = (Vector2)Tag;
            Position = OriginalPosition + MouseDelta;
        }

        void Translatable.Snap(Snapper Snapper)
        {
            Position = Snapper.SnapPosition(Position);
        }

        #endregion

        #region Rotatable Members

        object Rotatable.PrepareToRotate()
        {
            return Angle;
        }

        void Rotatable.ApplyRotation(object Tag, float Rotation)
        {
            float OriginalAngle = (float)Tag;
            Angle = OriginalAngle + Rotation;
        }

        void Rotatable.Snap(Snapper Snapper)
        {
            Angle = Snapper.SnapRotation(Angle);
        }

        #endregion

        #region Scalable Members

        object Scalable.PrepareToScale()
        {
            return Scale;
        }

        void Scalable.ApplyScale(object Tag, float Delta)
        {
            Scale = (float)Tag + Delta;
        }

        void Scalable.Snap(Snapper Snapper)
        {
            Scale = Snapper.SnapScale(Scale);
        }

        #endregion

        [ContentSerializerIgnore]
        public int ReferenceID { get; set; }

        public Vector2 GetWorldPosition()
        {
            if (Owner == null) return Position;
            else return Owner.Position + Position;
        }

        void Engine.Renderer.IDrawable.Draw(Engine.Renderer.RenderEffect Effect, 
            Engine.Renderer.VertexPusher Pusher, Engine.EpisodeContentManager Content)
        {
            Effect.PushMatrix(
                Matrix.CreateScale(new Vector3(new Vector2(Scale * AspectRatio, Scale), 0.0f)) *
                Matrix.CreateRotationZ(Angle) *
                Matrix.CreateTranslation(new Vector3(Position, 0.0f)));
            Effect.Texture = Content.GetTexture(Texture);
            Effect.Color = Tint;
            Pusher.DrawSprite(Flip);
            Effect.PopMatrix();            
        }
    }
}
